use std::thread;

const NTHREADS: usize = 10;

pub fn practice() {
    // 这是我们要处理的数据。
    // 我们会通过线程实现 map-reduce 算法，从而计算每一位的和
    // 每个用空白符隔开的块都会分配给单独的线程来处理
    //
    // 试一试：插入空格，看看输出会怎样变化！
    let data = "86967897737416471853297327050364959
11861322575564723963297542624962850
70856234701860851907960690014725639
38397966707106094172783238747669219
52380795257888236525459303330302837
58495327135744041048897885734297812
69920216438980873548808413720956532
16278424637452589860345374828574668";

    // 创建一个向量，用于储存将要创建的子线程
    let mut children = vec![];

    /*************************************************************************
     * "Map" 阶段
     *
     * 把数据分段，并进行初始化处理
     ************************************************************************/

    let page_size = data.len() / NTHREADS;
    let more_size = data.len() % NTHREADS;

    for i in 0..NTHREADS {
        let mut data_len = page_size;
        if i == NTHREADS - 1 {
            data_len += more_size;
        }

        let skip_len = i * page_size;
        let data_segment = &data[skip_len..skip_len + data_len];
        println!("data segment {} is \"{}\"", i, data_segment);

        children.push(thread::spawn(move || {
            // 计算该段的每一位的和：
            let result = data_segment
                // 对该段中的字符进行迭代..
                .chars()
                // 过滤掉非数字
                .filter(|c| c.is_numeric())
                // ..把字符转成数字..
                .map(|c| c.to_digit(10).expect("should be a digit"))
                // ..对返回的数字类型的迭代器求和
                .sum();

            // println! 会锁住标准输出，这样各线程打印的内容不会交错在一起
            println!("processed segment {}, result={}", i, result);

            // 不需要 “return”，因为 Rust 是一种 “表达式语言”，每个代码块中
            // 最后求值的表达式就是代码块的值。
            result
        }));
    }

    /*************************************************************************
     * "Reduce" 阶段
     *
     * 收集中间结果，得出最终结果
     ************************************************************************/

    // 把每个线程产生的中间结果收入一个新的向量中
    let mut intermediate_sums = vec![];
    for child in children {
        // 收集每个子线程的返回值
        let intermediate_sum = child.join().unwrap();
        intermediate_sums.push(intermediate_sum);
    }

    // 把所有中间结果加起来，得到最终结果
    //
    // 我们用 “涡轮鱼” 写法 ::<> 来为 sum() 提供类型提示。
    //
    // 试一试：不使用涡轮鱼写法，而是显式地指定 intermediate_sums 的类型
    let final_result = intermediate_sums.iter().sum::<u32>();

    println!("Final sum result: {}", final_result);
}
